/**
 *   Copyright 2014 Royce Remulla
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package cjcast.y2015.problem;

import java.util.ArrayList;
import java.util.List;


/**
 * @author royce.com@gmail.com
 */
@SuppressWarnings("PMD.SystemPrintln")
public final class LEDPrinter {


    /** LED Display Segment. */
    enum Segment {

        /** */
        Top(Byte.parseByte("1000000", 2)),
        /** */
        TopRight(Byte.parseByte("0100000", 2)),
        /** */
        TopLeft(Byte.parseByte("0000010", 2)),

        /** */
        BottomRight(Byte.parseByte("0010000", 2)),
        /** */
        Bottom(Byte.parseByte("0001000", 2)),
        /** */
        BottomLeft(Byte.parseByte("0000100", 2)),

        /** */
        Middle(Byte.parseByte("0000001", 2));

        /** */
        private final transient byte value;

        Segment(final byte pValue) {
            value = pValue;
        }


        public byte getValue()
        {
            return value;
        }

    }


    /**
     * @param ledRaw LED states in raw format.
     */
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
    public static void print(final byte... ledRaw)
    {
        assert ledRaw != null && ledRaw.length > 0;

        if (SevensegmentDisplay.ERROR_OUTPUT.equals(ledRaw[0])) {
            System.out.println(ledRaw);
        } else {
            final List<LEDState> ledStateList = new ArrayList<LEDState>();
            for (final byte nextRaw : ledRaw) {
                ledStateList.add(new LEDState(nextRaw));
            }

            print(ledStateList.toArray(new LEDState[ledRaw.length]));
        }
    }


    /**
     * @param ledRaw LED states in raw format.
     */
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
    public static void print(final String... ledRaw)
    {
        assert ledRaw != null && ledRaw.length > 0;

        if (SevensegmentDisplay.ERROR_OUTPUT.equals(ledRaw[0])) {
            System.out.println(SevensegmentDisplay.ERROR_OUTPUT);
        } else {
            final List<LEDState> ledStateList = new ArrayList<LEDState>();
            for (final String nextRaw : ledRaw) {
                ledStateList.add(new LEDState(nextRaw));
            }

            print(ledStateList.toArray(new LEDState[ledRaw.length]));
        }
    }


    /**
     * @param ledStates LED states.
     */
    public static void print(final LEDState... ledStates)
    {
        final StringBuilder strBuilder = new StringBuilder();

        for (final LEDState nextLedState : ledStates) {
            buildRow1(strBuilder, nextLedState);
            strBuilder.append("  ");
        }

        strBuilder.append('\n');
        for (final LEDState nextLedState : ledStates) {
            buildRow2(strBuilder, nextLedState);
            strBuilder.append("  ");
        }
        strBuilder.append('\n');
        for (final LEDState nextLedState : ledStates) {
            buildRow3(strBuilder, nextLedState);
            strBuilder.append("  ");
        }

        System.out.println(strBuilder.toString());
    }

    //    ._. . .
    //    |_| . .
    //    |_| . .


    /**
     * Generic LED row builder.
     * 
     * @param strBuilder string builder. For continuity of building multiple
     *            rows.
     * @param lEDState LED state.
     * @param position
     * @param onChar
     * @param offChar
     */
    static void buildRow(final StringBuilder strBuilder,
            final LEDState lEDState, final Segment position, final char onChar,
            final char offChar)
    {

        if ((lEDState.getByteValue() & position.getValue()) > 0) {
            strBuilder.append(onChar);
        } else {
            strBuilder.append(offChar);
        }
    }


    static void buildRow1(final StringBuilder strBuilder,
            final LEDState nextLedState)
    {
        strBuilder.append('.');
        buildRow(strBuilder, nextLedState, Segment.Top, '_', ' ');
        strBuilder.append('.');
    }

    static void buildRow2(final StringBuilder strBuilder,
            final LEDState nextLedState)
    {

        buildRow(strBuilder, nextLedState, Segment.TopLeft, '|', '.');
        buildRow(strBuilder, nextLedState, Segment.Middle, '_', ' ');
        buildRow(strBuilder, nextLedState, Segment.TopRight, '|', '.');
    }

    static void buildRow3(final StringBuilder strBuilder,
            final LEDState nextLedState)
    {
        buildRow(strBuilder, nextLedState, Segment.BottomLeft, '|', '.');
        buildRow(strBuilder, nextLedState, Segment.Bottom, '_', ' ');
        buildRow(strBuilder, nextLedState, Segment.BottomRight, '|', '.');
    }


    /** Utility class. */
    private LEDPrinter() {}

    /**
     * @param args unused.
     */
    public static void main(final String[] args)
    {
        LEDPrinter.print(new LEDState("1111111"), new LEDState("1100111"));

    }

}
